package org.server.http.core;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 接受请求
 * 
 * @author Admin
 * 
 */
public class AcceptRequest {
	// 套接字输入、输出封装的对象实例
	private SwapStream currenter;
	private HttpRequest request;
	// POST数据大允许的长度
	public static final int POST_DATA_MAX_SIZE = 1024 * 1024 * 2;// 2m
	// 编码类型
	private final static String CHARSET = "utf-8";

	/**
	 * 构造请求对象
	 * 
	 * @param current
	 * @throws IOException
	 */
	public AcceptRequest(SwapStream current) throws IOException {
		currenter = current;
		request = new HttpRequest();
		// 数据读取流
		request.setInputStream(currenter.inputStream());
	}

	/**
	 * 解析请求头，验证是否符合规范
	 * 
	 * @return
	 * @throws IOException
	 */
	public boolean validationRequestHeader() throws IOException {
		// 第一行，读取请求位置
		String frist = currenter.readNextHeader(CHARSET);
		if (frist == null) {
			// 请求头有问题，拒绝响应
			return false;
		}
		// 解析请求方法
		int starts = frist.indexOf(' ');
		int ends = frist.lastIndexOf(' ');
		if ((starts == -1) || (ends == -1)) {
			// 请求头有问题，拒绝响应
			return false;
		}
		request.setMethod(frist.substring(0, starts).toUpperCase());
		// 读取路径
		String url = frist.substring(starts + 1, ends);
		if (url == null) {
			return false;
		}
		if (url.startsWith("http://")) {
			// 绝对路径定位，截取相对路径
			int s = url.indexOf("/", 7);
			if (s != -1) {
				// 可能直接输入域名
				url = url.substring(s);
			} else {
				// 默认为首页
				url = "/";
			}
		}
		// 解释servlet路径
		int n = url.indexOf("?");
		if (n == -1) {
			request.setServletPath(url);
		} else {
			request.setServletPath(url.substring(0, n));
			// 解析请求字符串
			request.setQueryString(url.substring(n + 1));
		}
		request.setRequestURI(url);
		// 读取各种请求头
		Map<String, String> header_map = new HashMap<String, String>();
		String str = currenter.readNextHeader(CHARSET);
		if (str == null) {
			return false;
		}
		while (!"".equals(str)) {
			// 使用冒号加空格分割
			String[] array = str.split(": ");
			if (array.length != 2) {
				continue;
			}
			header_map.put(array[0], array[1]);
			str = currenter.readNextHeader(CHARSET);
		}
		// 解析参数URL
		parseRequestParams(request.getQueryString());
		if ("POST".equals(request.getMethod())) {
			// 尝试解析请求资源
			String params_length_str = header_map.get("Content-Length");
			if (params_length_str != null) {
				// 获取发送数据的字符长度
				int length = Integer.parseInt(params_length_str);
				if (length > POST_DATA_MAX_SIZE) {
					// 超出POST请求限制
					return false;
				}
				// 解析POST参数
				parseRequestParams(new String(this.readPostBytes(length), CHARSET));
			}
		}
		return true;
	}

	// 解析请求字符串
	private void parseRequestParams(String str) throws UnsupportedEncodingException {
		if (str == null) {
			return;
		}
		Map<String, String[]> params = new HashMap<String, String[]>();
		// 尝试解析所有参数
		String[] array = str.split("&");
		for (String entry : array) {
			String[] keyed = entry.split("=");
			if (keyed.length != 2) {
				continue;
			}
			String key = URLDecoder.decode(keyed[0], CHARSET);
			String value = URLDecoder.decode(keyed[1], CHARSET);
			// 将值解码
			String[] values = params.get(key);
			if (values == null) {
				// 不存在
				values = new String[1];
				values[0] = value;
				params.put(key, values);
			} else {
				String[] temp = new String[values.length + 1];
				for (int j = 0; j < temp.length - 1; j++) {
					temp[j] = values[j];
				}
				// 添加新值
				temp[temp.length - 1] = value;
				// 更新映射
				params.put(key, values);
			}
		}
		// 设置到响应对象
		request.setParamsMap(params);
	}

	/**
	 * 读取分包块的响应消息
	 * 
	 * @return
	 * @throws IOException
	 */
	private byte[] readPostBytes(int size) throws SocketTimeoutException, IOException {
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		// 构建最大缓冲区
		byte[] data = new byte[size];
		// 尝试尽可能多的读取
		int i = currenter.read(data);
		while (i > 0) {
			// 写入一次读取的次数
			stream.write(data, 0, i);
			// 获取还未读取的字节长度
			size = size - i;
			// 重新构建缓冲区
			data = new byte[size];
			i = currenter.read(data);
		}
		return stream.toByteArray();
	}

	/**
	 * 返回请求对象
	 * 
	 * @return
	 */
	public HttpRequest getRequest() {
		return request;
	}

	/**
	 * 设置远程地址
	 * 
	 * @param remoteAddr
	 */
	public void setRemoteAddr(String remoteAddr) {
		request.setRemoteAddr(remoteAddr);
	}
}
